package cn.bonoon.kernel;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import cn.bonoon.kernel.menus.ModuleDefinition;
import cn.bonoon.kernel.menus.ModuleManager;
import cn.bonoon.kernel.support.IOperator;
import cn.bonoon.kernel.support.models.Item;

/**
 * 用户访问权限的解析器
 * 用户每一次访问的时候生成
 * 
 * 注意：这个对象只能用于解释用户权限的访问，不能进行数据的保存操作，因为可能没有打开事务
 * 
 * 这里应该相当于一个子{@link ModuleDefinition}的一个实例
 * 
 * @author jackson
 *
 */
public class AccessAuthorityResolver {
	
	@Autowired
	private ModuleManager moduleManager;
	
	@PersistenceContext
	private EntityManager entityManager;
	
	private final IOperator user;
	
	/** 暂时缓存用户访问系统权限的一些信息 */
	private Collection<ModuleDefinition> myModules;
	
	/** 当前正要进入的子系统 */
	private ModuleDefinition currentModule;
	
	/** 关于当前用户访问权限解析时需要提示用户的信息 */
	private List<String> messages = new ArrayList<>(1);
	
	public static AccessAuthorityResolver valueOf(ApplicationContext applicationContext){
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		IOperator user = null;
		if (null != authentication) {
			Object principal = authentication.getPrincipal();
			if(principal instanceof IOperator){
				user = (IOperator)principal;
			}
		}
		return valueOf(applicationContext, user);
	}
	
	public static AccessAuthorityResolver valueOf(ApplicationContext applicationContext, IOperator user){
		AccessAuthorityResolver resolver = new AccessAuthorityResolver(user);
		applicationContext.getAutowireCapableBeanFactory().autowireBean(resolver);
		return resolver;
	}
	
	public ModuleDefinition toggle(String key){
		return currentModule = moduleManager.module(key);
	}
	
	/** 表示进入系统的平台 */
	public ModuleDefinition platform(){
		return currentModule = moduleManager.module();
	}
	
	private AccessAuthorityResolver(IOperator user){
		this.user = user;
	}
	
	public Collection<ModuleDefinition> resolveModules(){
		if(null == myModules){
			myModules = new ArrayList<>();
			if (user.isSuper()) {
				myModules.addAll(moduleManager.modules());
			} else {
				for (String key : hadAuthorities()) {
					ModuleDefinition module = moduleManager.module(key);
					if (null != module) {
						myModules.add(module);
					}
				}
			}
		}
		return myModules;
	}
	
	/** 当前我能访问的所有子系统列表，包括：ID、名字 */
	public List<Item> moduleItems(){
		return moduleItems(Collections.<String>emptyList());
	}
	
	/** 返回的结果被设置了是否选中的值 
	 * 参考：{@link #moduleItems()} */
	public List<Item> moduleItems(List<String> selecteds){
		List<Item> items = new ArrayList<Item>();
		for (ModuleDefinition module : resolveModules()) {
			addTo(items, module, selecteds);
		}
		return items;
	}
	
	/** 从定义的角色中解释我能访问的子系统 */
	private final String keyFromRole = "select distinct x.role.moduleKey " +
			"from RoleAccountEntity x " +
			"where x.account.id=? and x.invalid=false and x.role.status=1 and x.role.deleted=false";
	
	/** 有访问权限，我可以访问的子系统 */
	private List<String> hadAuthorities(){
		/*
		 * 需要从多个地方解释我所能访问的子系统；
		 * 包括角色、用户直接分配的权限、用户组等
		 */
		TypedQuery<String> tqSelect = entityManager.createQuery(keyFromRole, String.class);
		tqSelect.setParameter(1, user.getId());
		return tqSelect.getResultList();
	}

	private void addTo(List<Item> items, ModuleDefinition module, List<String> selecteds){
		Item item = new Item(module.getId(), module.getName());
		item.setSelected(selecteds.contains(module.getId()));
		items.add(item);
	}
	
	public ModelAndView gotoHome(){
		return new ModelAndView(new RedirectView(moduleManager.getDefaultEndpoint()));
	}
	
	/** 不需要登录就可以访问 */
	public String homeUrl(){
		return moduleManager.getDefaultEndpoint();
	}
	
	/** 当前用户必须处于登录状态 */
	public String plaformUrl(){
		return moduleManager.getEndpoint();
	}
	
	public ModuleDefinition visitModule(String key){
		for (ModuleDefinition module : resolveModules()) {
			if(key.equals(module.getId())) return module;
		}
		
		throw new RuntimeException("子系统不存在或没有访问权限！");
	}
}
